{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 多线程访问同一个列表导致冲突的问题\n",
    "\n",
    "两个线程同时往一个 List 中加入`MAX_COUNT`个数，最终 List 的数量有可能并非是`2 * MAX_COUNT`\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0:数量20\n",
      "1:数量10\n",
      "10, 11, 12, 13, 14, 15, 16, 17, 18, 19\n",
      "2:数量18\n",
      "10, 11, 12, 13, 14, 15, 16, 17, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9\n",
      "3:数量20\n",
      "4:数量20\n",
      "5:数量20\n",
      "6:数量20\n",
      "7:数量20\n",
      "8:数量20\n",
      "9:数量20\n"
     ]
    }
   ],
   "source": [
    "#load \"LoadBaseToolWPF.csx\"\n",
    "using BaseTool;\n",
    "using System.Threading;\n",
    "using System.IO;\n",
    "\n",
    "const int MAX_COUNT = 10;\n",
    "int _count = 0;\n",
    "while (_count < MAX_COUNT)\n",
    "{\n",
    "    List<int> list = new List<int>();\n",
    "\n",
    "    Task _task1 = Task.Run(() =>\n",
    "    {\n",
    "        for (int i = 0; i < MAX_COUNT; i++) { list.Add(i); }\n",
    "    });\n",
    "\n",
    "    Task _task2 = Task.Run(() =>\n",
    "    {\n",
    "        for (int i = MAX_COUNT; i < 2 * MAX_COUNT; i++) { list.Add(i); }\n",
    "    });\n",
    "\n",
    "    Task.WaitAll(_task1, _task2);\n",
    "\n",
    "    // 当长度对不上时，输出详细内容\n",
    "    Console.WriteLine($\"{_count++}:数量{list.Count}\");\n",
    "    if (list.Count != MAX_COUNT * 2) { list.Dump(); }\n",
    "    Thread.Sleep(1000);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 测试直接运行异步函数，而不使用 await 关键字的运行情况\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello World\n",
      "运行耗时：2000ms\n"
     ]
    }
   ],
   "source": [
    "using System.Diagnostics;\n",
    "\n",
    "Stopwatch _sw = Stopwatch.StartNew();\n",
    "await Function();\n",
    "_sw.Stop();\n",
    "Console.WriteLine($\"运行耗时：{_sw.ElapsedMilliseconds}ms\");\n",
    "\n",
    "// 这是一个异步函数，如果不直接执行，则会直接跳过\n",
    "public async Task Function()\n",
    "{\n",
    "    await Task.Delay(2000);\n",
    "    Console.WriteLine(\"Hello World\");\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "运行耗时：0ms\r\n"
     ]
    }
   ],
   "source": [
    "using System.Diagnostics;\n",
    "\n",
    "Stopwatch _sw = Stopwatch.StartNew();\n",
    "Function();\n",
    "_sw.Stop();\n",
    "Console.WriteLine($\"运行耗时：{_sw.ElapsedMilliseconds}ms\");"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 多线程打断等待测试\n",
    "\n",
    "- 任务 1 持续循环，等待任务 2 打断后，再过 1 秒，结束。\n",
    "- 任务 2 等待 2 秒，打断任务 1，等待任务 1 完全结束，也结束。\n",
    "\n",
    "这里有个问题：\n",
    "如果任务 2 中没有`await _task`，即取消后就结束任务 2，那么任务 1 最终就不会执行。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "任务1结束\n",
      "任务2结束\n"
     ]
    }
   ],
   "source": [
    "using System.Threading.Tasks;\n",
    "\n",
    "CancellationTokenSource _cts = new CancellationTokenSource();\n",
    "Task _task = Task.Run(()=>\n",
    "{\n",
    "    while(true)\n",
    "    {\n",
    "        if(_cts.IsCancellationRequested) break;\n",
    "    }\n",
    "    Task.Delay(1000).Wait();\n",
    "    Console.WriteLine(\"任务1结束\");\n",
    "});\n",
    "\n",
    "await Task.Run(async ()=>\n",
    "{\n",
    "    Task.Delay(2000).Wait();\n",
    "    _cts.Cancel();\n",
    "    await _task;\n",
    "    Console.WriteLine(\"任务2结束\");\n",
    "});"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `TaskCompletionSource` 相关状态\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "初始状态: WaitingForActivation\n",
      "TrySetCanceled: Canceled\n",
      "TrySetResult: RanToCompletion\n",
      "TrySetException: Faulted\n"
     ]
    }
   ],
   "source": [
    "TaskCompletionSource _source1 = new TaskCompletionSource();\n",
    "Console.WriteLine($\"初始状态: {_source1.Task.Status}\");\n",
    "\n",
    "_source1.TrySetCanceled();\n",
    "Console.WriteLine($\"TrySetCanceled: {_source1.Task.Status}\");\n",
    "\n",
    "TaskCompletionSource _source2 = new TaskCompletionSource();\n",
    "_source2.TrySetResult();\n",
    "Console.WriteLine($\"TrySetResult: {_source2.Task.Status}\");\n",
    "\n",
    "\n",
    "TaskCompletionSource _source3 = new TaskCompletionSource();\n",
    "_source3.TrySetException(new Exception());\n",
    "Console.WriteLine($\"TrySetException: {_source3.Task.Status}\");"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `Task` 状态\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Task运行: WaitingToRun\n",
      "Task取消: Canceled\n",
      "Task异常: Faulted\n"
     ]
    }
   ],
   "source": [
    "using System.Threading;\n",
    "\n",
    "CancellationTokenSource _source = new();\n",
    "_source.Cancel();\n",
    "Console.WriteLine($\"Task运行: {Task.Run(()=>{}).Status}\");\n",
    "Console.WriteLine($\"Task取消: {Task.FromCanceled(_source.Token).Status}\");\n",
    "Console.WriteLine($\"Task异常: {Task.FromException(new Exception()).Status}\");"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 不能理解的地方\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Task1: WaitingForActivation\n",
      "Task1: Running\n",
      "Task1: Running\n",
      "Task1: RanToCompletion\n",
      "Task1: RanToCompletion\n",
      "Task1: RanToCompletion\n"
     ]
    }
   ],
   "source": [
    "Task _task1 = Task.Delay(1000);\n",
    "Task _task2 = Task.Run(()=>{ Task.Delay(1000).Wait(); });\n",
    "Task _task3 = new Task(()=>{ Task.Delay(1000).Wait(); });\n",
    "_task3.Start();\n",
    "\n",
    "// 任务运行中\n",
    "Task.Delay(100).Wait();\n",
    "Console.WriteLine($\"Task1: {_task1.Status}\");\n",
    "Console.WriteLine($\"Task1: {_task2.Status}\");\n",
    "Console.WriteLine($\"Task1: {_task3.Status}\");\n",
    "\n",
    "// 所有的任务完成\n",
    "Task.Delay(1100).Wait();\n",
    "Console.WriteLine($\"Task1: {_task1.Status}\");\n",
    "Console.WriteLine($\"Task1: {_task2.Status}\");\n",
    "Console.WriteLine($\"Task1: {_task3.Status}\");"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [],
   "source": [
    "int value = 10 / 3;\n",
    "value.Display();\n",
    "\n",
    "int value01 = 10 % 3;\n",
    "value01.Display();\n",
    "\n",
    "object _obj = new object();\n",
    "\n",
    "int _int_value = 0;\n",
    "_ = Task.Run(() =>\n",
    "{\n",
    "    lock (new object())\n",
    "    {\n",
    "        for (int i = 0; i < 2000; i++) \n",
    "        { \n",
    "            _int_value++; \n",
    "        };\n",
    "        Console.WriteLine($\"1:{_int_value}\");\n",
    "    }\n",
    "});\n",
    "\n",
    "_ = Task.Run(() =>\n",
    "{\n",
    "    lock (new object())\n",
    "    {\n",
    "        for (int i = 0; i < 2000; i++) { _int_value++; };\n",
    "        Console.WriteLine($\"2:{_int_value}\");\n",
    "    }\n",
    "});"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "count = 14427\n",
      "count = 15790913\n",
      "count = 31729677\n",
      "count = 47635554\n",
      "count = 63453014\n",
      "count = 79166046\n",
      "count = 95005539\n",
      "count = 110614539\n",
      "Task Over on ContinueWith\n",
      "Catch Exception\n"
     ]
    }
   ],
   "source": [
    "\n",
    "using System.Threading;\n",
    "double _sum = 0;\n",
    "\n",
    "int _count = 0;\n",
    "bool _is_running = true;\n",
    "\n",
    "CancellationTokenSource _cts = new();\n",
    "\n",
    "try\n",
    "{\n",
    "    _ = Task.Run(()=>\n",
    "    {\n",
    "        while(_is_running) \n",
    "        { \n",
    "            Console.WriteLine($\"count = {_count}\");\n",
    "            if(_count > 1e8)\n",
    "            {\n",
    "                _cts.Cancel();\n",
    "                throw new InvalidOperationException();  \n",
    "            } \n",
    "            Task.Delay(100).Wait();\n",
    "        }\n",
    "\n",
    "        Console.WriteLine(\"Task Over\");\n",
    "    }).ContinueWith((_)=>\n",
    "    {\n",
    "        Console.WriteLine(\"Task Over on ContinueWith\");\n",
    "        throw new Exception();\n",
    "    }, TaskContinuationOptions.OnlyOnFaulted);\n",
    "\n",
    "    for(int i = 1; i < 1e9; i++)\n",
    "    {\n",
    "        _cts.Token.ThrowIfCancellationRequested();\n",
    "        _count ++;\n",
    "        _sum += (_sum / i + 1);\n",
    "    }\n",
    "    _is_running = false;\n",
    "\n",
    "    Console.WriteLine(_sum);\n",
    "}\n",
    "catch\n",
    "{\n",
    "    Console.WriteLine(\"Catch Exception\");\n",
    "}\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Main Over\n",
      "WaitingForActivation\n",
      "WaitingForActivation\n",
      "WaitingForActivation\n",
      "FireAndForget\n",
      "RanToCompletion\n"
     ]
    }
   ],
   "source": [
    "static async Task FireAndForget()\n",
    "{\n",
    "    await Task.Delay(2000);\n",
    "    Console.WriteLine(\"FireAndForget\");\n",
    "}\n",
    "\n",
    "var _task = FireAndForget();\n",
    "Console.WriteLine(\"Main Over\");\n",
    "Console.WriteLine(_task.Status);\n",
    "await Task.Delay(1000);\n",
    "Console.WriteLine(_task.Status);\n",
    "await Task.Delay(1000);\n",
    "Console.WriteLine(_task.Status);\n",
    "await Task.Delay(1000);\n",
    "Console.WriteLine(_task.Status);\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Main Over\n",
      "WaitingForActivation\n",
      "WaitingForActivation\n",
      "FireAndForget\n",
      "RanToCompletion\n",
      "RanToCompletion\n"
     ]
    }
   ],
   "source": [
    "static async Task FireAndForget()\n",
    "{\n",
    "    await Task.Delay(2000).ConfigureAwait(false);\n",
    "    Console.WriteLine(\"FireAndForget\");\n",
    "}\n",
    "\n",
    "var _task = FireAndForget();\n",
    "Console.WriteLine(\"Main Over\");\n",
    "Console.WriteLine(_task.Status);\n",
    "await Task.Delay(1000);\n",
    "Console.WriteLine(_task.Status);\n",
    "await Task.Delay(1000);\n",
    "Console.WriteLine(_task.Status);\n",
    "await Task.Delay(1000);\n",
    "Console.WriteLine(_task.Status);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Main 方法开始，当前线程: 10\n",
      "Main 方法继续执行，当前线程: 10\n",
      "FireAndForget 开始，当前线程: 61\n",
      "FireAndForget 中的 Console.WriteLine，当前线程: 62\n"
     ]
    }
   ],
   "source": [
    "Console.WriteLine($\"Main 方法开始，当前线程: {Environment.CurrentManagedThreadId}\");\n",
    "_ = Task.Run(FireAndForget);\n",
    "Console.WriteLine($\"Main 方法继续执行，当前线程: {Environment.CurrentManagedThreadId}\");\n",
    "await Task.Delay(5000);\n",
    "\n",
    "static async Task FireAndForget()\n",
    "{\n",
    "    Console.WriteLine($\"FireAndForget 开始，当前线程: {Environment.CurrentManagedThreadId}\");\n",
    "    await Task.Delay(2000).ConfigureAwait(false);\n",
    "    Console.WriteLine($\"FireAndForget 中的 Console.WriteLine，当前线程: {Environment.CurrentManagedThreadId}\");\n",
    "}\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Main 方法开始，当前线程: 10\n",
      "Main 方法继续执行，当前线程: 10\n",
      "FireAndForget 开始，当前线程: 61\n",
      "FireAndForget 中的 Console.WriteLine，当前线程: 37\n"
     ]
    }
   ],
   "source": [
    "Console.WriteLine($\"Main 方法开始，当前线程: {Environment.CurrentManagedThreadId}\");\n",
    "_ = Task.Run(FireAndForget);\n",
    "Console.WriteLine($\"Main 方法继续执行，当前线程: {Environment.CurrentManagedThreadId}\");\n",
    "await Task.Delay(5000);\n",
    "\n",
    "static async Task FireAndForget()\n",
    "{\n",
    "    Console.WriteLine($\"FireAndForget 开始，当前线程: {Environment.CurrentManagedThreadId}\");\n",
    "    await Task.Delay(2000);\n",
    "    Console.WriteLine($\"FireAndForget 中的 Console.WriteLine，当前线程: {Environment.CurrentManagedThreadId}\");\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Main 方法开始，当前线程: 10\n",
      "FireAndForget 开始，当前线程: 10\n",
      "Main 方法继续执行，当前线程: 10\n",
      "FireAndForget 中的 Console.WriteLine，当前线程: 37\n"
     ]
    }
   ],
   "source": [
    "Console.WriteLine($\"Main 方法开始，当前线程: {Environment.CurrentManagedThreadId}\");\n",
    "_ = FireAndForget();\n",
    "Console.WriteLine($\"Main 方法继续执行，当前线程: {Environment.CurrentManagedThreadId}\");\n",
    "await Task.Delay(5000);\n",
    "\n",
    "static async Task FireAndForget()\n",
    "{\n",
    "    Console.WriteLine($\"FireAndForget 开始，当前线程: {Environment.CurrentManagedThreadId}\");\n",
    "    await Task.Delay(2000);\n",
    "    Console.WriteLine($\"FireAndForget 中的 Console.WriteLine，当前线程: {Environment.CurrentManagedThreadId}\");\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Main 方法开始，当前线程: 10\n",
      "FireAndForget 开始，当前线程: 10\n",
      "Main 方法继续执行，当前线程: 10\n",
      "FireAndForget 中的 Console.WriteLine，当前线程: 29\n"
     ]
    }
   ],
   "source": [
    "Console.WriteLine($\"Main 方法开始，当前线程: {Environment.CurrentManagedThreadId}\");\n",
    "_ = FireAndForget();\n",
    "Console.WriteLine($\"Main 方法继续执行，当前线程: {Environment.CurrentManagedThreadId}\");\n",
    "await Task.Delay(5000);\n",
    "\n",
    "static async Task FireAndForget()\n",
    "{\n",
    "    Console.WriteLine($\"FireAndForget 开始，当前线程: {Environment.CurrentManagedThreadId}\");\n",
    "    await Task.Delay(2000).ConfigureAwait(false);\n",
    "    Console.WriteLine($\"FireAndForget 中的 Console.WriteLine，当前线程: {Environment.CurrentManagedThreadId}\");\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "10\n",
      "55\n",
      "55\n",
      "55\n",
      "55\n",
      "50\n",
      "50\n",
      "50\n",
      "55\n",
      "50\n",
      "End:50\n"
     ]
    }
   ],
   "source": [
    "public async void Loop()\n",
    "{\n",
    "    while(true)\n",
    "    {\n",
    "        await Task.Delay(1000).ConfigureAwait(false);\n",
    "        Console.WriteLine($\"{Environment.CurrentManagedThreadId}\");\n",
    "    }\n",
    "}\n",
    "\n",
    "Console.WriteLine($\"{Environment.CurrentManagedThreadId}\");\n",
    "_ = Task.Run(Loop);\n",
    "await Task.Delay(10000).ConfigureAwait(true);\n",
    "Console.WriteLine($\"End:{Environment.CurrentManagedThreadId}\");"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".NET (C#)",
   "language": "C#",
   "name": ".net-csharp"
  },
  "language_info": {
   "name": "csharp"
  },
  "polyglot_notebook": {
   "kernelInfo": {
    "defaultKernelName": "csharp",
    "items": [
     {
      "aliases": [],
      "name": "csharp"
     }
    ]
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
